﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Security.Cryptography; 
using System.Text;
using System.Management;
using System.Management.Instrumentation;
using Microsoft.Win32;

namespace SysMisc
{
    //=====================================================
    //Copyright (C) 2013 Chen
    //All rights reserved
    //CLR版本:            2.0.50727.1433
    //类名称: SoftReg
    //类功能: 完成相关注册验证功能的类
    //======================================================
    public class SoftReg
    {
        //验证模式
        public enum CheckMode
        {
            CountOnly,//只验证次数
            DateOnly,//只验证时间
            CountAndDate,//验证次数和时间
            CountOrDate//验证次数或时间
        }
        public enum StatusMode
        {
            InputEmpty,//字符串为空
            RegFailed,//注册失败
            unRegisted,//未注册
            Registed,//已注册
            Expired,//已过期
        }

        //私有变量
        private Int32 _n32MaxDay;//最大使用天数
        private Int32 _n32MaxCount;//最大使用次数
        private Int32 _n32RandSeed;
        private CheckMode _cmLoadCheck;
        private string _strUsrName;
        private string _strRegKey;

        //构造函数
        public SoftReg( string strUsrName )
        {
            Random rd = new Random();
            _n32RandSeed = rd.Next();
            _cmLoadCheck = CheckMode.DateOnly;
            _n32MaxCount = 30;//最多30次
            _n32MaxDay = 30;//最大30天
            _strUsrName = strUsrName;
            _strRegKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JiuYang";
        }


        //生成机器码
        public string getMNum()
        {
            string strNum = getCpu() + GetDiskVolumeSerialNumber();//获得24位Cpu和硬盘序列号
            string strMNum = strNum.Substring(0, 24);//从生成的字符串中取出前24个字符做为机器码
            return strMNum;
        }

        public int[] intCode = new int[127];//存储密钥
        public int[] intNumber = new int[25];//存机器码的Ascii值
        public char[] Charcode = new char[25];//存储机器码字

        private void setIntCode()//给数组赋值小于10的数
        {
            for (int i = 1; i < intCode.Length; i++)
            {
                intCode[i] = i % 9;
            }
        }

        //生成注册码
        public string getRNum()
        {
            setIntCode();//初始化127位数组
            string strMNum = this.getMNum();
            for (int i = 1; i < Charcode.Length; i++)//把机器码存入数组中
            {
                Charcode[i] = Convert.ToChar(strMNum.Substring(i - 1, 1));
            }
            for (int j = 1; j < intNumber.Length; j++)//把字符的ASCII值存入一个整数组中。
            {
                intNumber[j] = intCode[Convert.ToInt32(Charcode[j])] + Convert.ToInt32(Charcode[j]);
            }
            string strAsciiName = "";//用于存储注册码
            for (int j = 1; j < intNumber.Length; j++)
            {
                if (intNumber[j] >= 48 && intNumber[j] <= 57)//判断字符ASCII值是否0－9之间
                {
                    strAsciiName += Convert.ToChar(intNumber[j]).ToString();
                }
                else if (intNumber[j] >= 65 && intNumber[j] <= 90)//判断字符ASCII值是否A－Z之间
                {
                    strAsciiName += Convert.ToChar(intNumber[j]).ToString();
                }
                else if (intNumber[j] >= 97 && intNumber[j] <= 122)//判断字符ASCII值是否a－z之间
                {
                    strAsciiName += Convert.ToChar(intNumber[j]).ToString();
                }
                else//判断字符ASCII值不在以上范围内
                {
                    if (intNumber[j] > 122)//判断字符ASCII值是否大于z
                    {
                        strAsciiName += Convert.ToChar(intNumber[j] - 10).ToString();
                    }
                    else
                    {
                        strAsciiName += Convert.ToChar(intNumber[j] - 9).ToString();
                    }
                }
            }
            return strAsciiName;
        }

        //验证注册码——注册验证
        public StatusMode checkRNum_Input(string SnIn)
        {
            if (SnIn == "")
            {
                return StatusMode.InputEmpty ;//为空
            }
            string SnTrue = getRNum();
            if (SnTrue.Equals(SnIn))
            {
                Registry.SetValue(_strRegKey, "SN", SnTrue);

                //更新注册表
                setCountLastLoad( _n32RandSeed );
                setCountOut(_n32RandSeed + _n32MaxCount);
                setDateLastLoad(DateTime.Now);
                setDateOut(DateTime.Now.AddDays( (double)_n32MaxDay ));
                return StatusMode.Registed ;//注册成功
            }
            else
            {
                return StatusMode.RegFailed ;//失败
            }
        }
        //验证注册码——登录验证
        public StatusMode checkRNum_Reg()
        {
            string strRNum = getRNum();
            try
            {
                string strSn = (string)Registry.GetValue(_strRegKey, "SN", 0);
                if (strSn.Equals(strRNum))
                {//说明曾经注册过，现在看看是否过期
                    bool bDate = IfDateOut();
                    bool bCount = IfCountOut();

                    switch (_cmLoadCheck)
                    {
                        case CheckMode.DateOnly:
                            if (bDate)
                            {
                                //更新注册表
                                setCountLastLoad(getCountLastLoad() + 1);
                                setDateLastLoad(DateTime.Now);
                                return StatusMode.Registed;
                            }
                            else
                                return StatusMode.Expired;
                        case CheckMode.CountOnly:
                            if (bCount)
                            {
                                //更新注册表
                                setCountLastLoad(getCountLastLoad() + 1);
                                setDateLastLoad(DateTime.Now);
                                return StatusMode.Registed;
                            }
                            else
                                return StatusMode.Expired;
                        case CheckMode.CountAndDate:
                            if (bDate && bCount)
                            {
                                //更新注册表
                                setCountLastLoad(getCountLastLoad() + 1);
                                setDateLastLoad(DateTime.Now);
                                return StatusMode.Registed;
                            }
                            else
                                return StatusMode.Expired;
                        case CheckMode.CountOrDate:
                            if (bDate || bCount)
                            {
                                //更新注册表
                                setCountLastLoad(getCountLastLoad() + 1);
                                setDateLastLoad(DateTime.Now);
                                return StatusMode.Registed;
                            }
                            else
                                return StatusMode.Expired;
                    }
                }
            }
            catch (Exception )
            {
                return StatusMode.unRegisted;
            }

            return StatusMode.unRegisted;//未注册
        }
        //返回/设置超时时间
        public DateTime getDateOut()
        {
            string strReg = (string)Registry.GetValue(_strRegKey, "DATEOUT", 0);
            DateTime dt = Convert.ToDateTime( Decode( strReg ) );
            return dt;
        }
        private void setDateOut(DateTime dtIn)
        {
            string strReg = dtIn.ToString();
            strReg = Encode(strReg);
            Registry.SetValue(_strRegKey, "DATEOUT", strReg );

        }
        //得到/设置上次登录时间
        public DateTime getDateLastLoad()
        {
            string strReg = (string)Registry.GetValue(_strRegKey, "DATELASTLOAD", 0);
            DateTime dt = Convert.ToDateTime( Decode( strReg ) );
            return dt;
        }
        private void setDateLastLoad(DateTime dtIn)
        {
            string strReg = dtIn.ToString();
            strReg = Encode(strReg);
            Registry.SetValue(_strRegKey, "DATELASTLOAD", strReg);
        }
        //得到/设置终止次数
        private Int32 getCountOut()
        {
            string strReg = (string)Registry.GetValue(_strRegKey, "COUNTOUT", 0);
            Int32 n32Count = Convert.ToInt32(Decode(strReg));
            return n32Count;
        }
        private void setCountOut( Int32 nIn )
        {
            string strReg = nIn.ToString();
            strReg = Encode(strReg);
            Registry.SetValue(_strRegKey, "COUNTOUT", strReg);
        }
        //得到/设置上次的次数
        private Int32 getCountLastLoad()
        {
            string strReg = (string)Registry.GetValue(_strRegKey, "COUNTLOAD", 0);
            Int32 n32Count = Convert.ToInt32(Decode(strReg));
            return n32Count;
        }
        private void setCountLastLoad( Int32 nIn )
        {
            string strReg = nIn.ToString();
            strReg = Encode(strReg);
            Registry.SetValue(_strRegKey, "COUNTLOAD", strReg);
        }

        // 取得设备硬盘的卷标号
        public string GetDiskVolumeSerialNumber()
        {
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"d:\"");
            disk.Get();
            return disk.GetPropertyValue("VolumeSerialNumber").ToString();
        }

        //获得CPU的序列号
        public string getCpu()
        {
            string strCpu = null;
            ManagementClass myCpu = new ManagementClass("win32_Processor");
            ManagementObjectCollection myCpuConnection = myCpu.GetInstances();
            foreach (ManagementObject myObject in myCpuConnection)
            {
                strCpu = myObject.Properties["Processorid"].Value.ToString();
                break;
            }
            return strCpu;
        }

        //加密
        public static string Encode(string data)
        {
            string KEY_64 = "VavicApp";
            string IV_64 = "VavicApp";
            byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);
            byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);
            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            int i = cryptoProvider.KeySize;
            MemoryStream ms = new MemoryStream();
            CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write);
            StreamWriter sw = new StreamWriter(cst);
            sw.Write(data);
            sw.Flush();
            cst.FlushFinalBlock();
            sw.Flush();
            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
        }
        //解密
        public static string Decode(string data)
        {
            string KEY_64 = "VavicApp";
            string IV_64 = "VavicApp";
            byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);
            byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);
            byte[] byEnc;
            try
            {
                byEnc = Convert.FromBase64String(data);
            }
            catch
            {
                return null;
            }
            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            MemoryStream ms = new MemoryStream(byEnc);
            CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read);
            StreamReader sr = new StreamReader(cst);
            return sr.ReadToEnd();
        }

        //是否超时
        private bool IfDateOut()
        {
            DateTime dtOut = getDateOut();
            DateTime dtLoad = getDateLastLoad();
            DateTime dtNow = DateTime.Now;
            if (DateTime.Compare(dtLoad, dtNow) > 0)//上一次加载时间大于现在时间（有可能他擅自调后时间）
                return false;
            else if (DateTime.Compare(dtNow, dtOut) > 0) //现在时间大于过期时间（已过期）
                return false;
            else
                return true;
        }
        //是否超次
        private bool IfCountOut()
        {
            Int32 n32Out = getCountOut();
            Int32 n32Load = getCountLastLoad();
            if (n32Load > n32Out)//超次
                return false;
            else
                return true;
        }
    }
}
